package com.unswift.window.editor;

import java.awt.Color;
import java.util.StringTokenizer;

import javax.swing.text.AttributeSet;
import javax.swing.text.BadLocationException;
import javax.swing.text.DefaultStyledDocument;
import javax.swing.text.Element;
import javax.swing.text.MutableAttributeSet;
import javax.swing.text.SimpleAttributeSet;
import javax.swing.text.StyleConstants;

import com.unswift.utils.FileUtils;
import com.unswift.utils.JsonUtils;
import com.unswift.utils.NumberUtils;
import com.unswift.utils.ObjectUtils;
import com.unswift.utils.ThreadUtils;
import com.unswift.window.undo.UndoAction;
import com.unswift.window.undo.UndoDocument;
import com.unswift.window.undo.UndoManager;

@SuppressWarnings("serial")
public class EditorDocument extends DefaultStyledDocument implements UndoDocument{

	private final static Color DEFAULT_COLOR=Color.BLACK;
	private final static Color KEYWORD_COLOR=new Color(127, 0, 85);
	private final static Color VARCHAR_COLOR=new Color(0, 0, 255);
	private final static Color NUMBER_COLOR=new Color(51, 102, 51);
	private final static Color NOTES_COLOR=new Color(187, 187, 187);
	private final static Color OK_COLOR=new Color(63, 127, 95);
	private final static Color ERROR_COLOR=Color.RED;
	
	private AttributeSet attribute;
	private Editor editor;
	private boolean isPushUndo=true;
	private boolean isNewAction=true;
	private int refreshColor=0;
	private boolean isShowQuickTips=true;
	private boolean isRedrawColor=true;
	
	public void setEditor(Editor editor) {
		this.editor = editor;
	}
	
	public void insertString(int offset, String text, AttributeSet attribute) throws BadLocationException {
		super.insertString(offset, text, attribute);
		if(isPushUndo){
			((UndoManager)editor.getAttribute(Editor.ATTRIBUTE_EDITOR_UNDO_MANAGER)).addEdit(new UndoAction(UndoAction.ACTION_INSERT, offset, text.length(), text), isNewAction);
		}
		if(ObjectUtils.isNotEmpty(attribute)){
			this.attribute=attribute;
			if(!attribute.containsAttribute("$ename", "content") && 
				(
					Editor.ACTION_AUTOMATION_JSON.equals(editor.getBusAction()) || 
					Editor.ACTION_INTERFACE_JSON.equals(editor.getBusAction()) ||
					Editor.ACTION_CREATE_INTERFACE_JSON.equals(editor.getBusAction())
				)
			){//输入中文时不管
				setForegroundColor();
			}else if(!attribute.containsAttribute("$ename", "content") && 
				(
					Editor.ACTION_AUTOMATION_CONSOLE.equals(editor.getBusAction()) || 
					Editor.ACTION_INTERFACE_CONSOLE.equals(editor.getBusAction()) ||
					Editor.ACTION_CREATE_INTERFACE_JSON.equals(editor.getBusAction())
			)){
				setForegroundColor2();
			}
		}
	}

	public void remove(int offset, int length) throws BadLocationException {
		if(isPushUndo){
			((UndoManager)editor.getAttribute(Editor.ATTRIBUTE_EDITOR_UNDO_MANAGER)).addEdit(new UndoAction(UndoAction.ACTION_REMOVE, offset, length, this.getText(offset, length)), isNewAction);
		}
		super.remove(offset, length);
		if(ObjectUtils.isNotEmpty(attribute)){
			if(!attribute.containsAttribute("$ename", "content") && 
				(
					Editor.ACTION_AUTOMATION_JSON.equals(editor.getBusAction()) || 
					Editor.ACTION_INTERFACE_JSON.equals(editor.getBusAction()) ||
					Editor.ACTION_CREATE_INTERFACE_JSON.equals(editor.getBusAction())
				)
			){//上一次记录输入的时中文，则不触发
				setForegroundColor();
			}else if(!attribute.containsAttribute("$ename", "content") && 
				(
					Editor.ACTION_AUTOMATION_CONSOLE.equals(editor.getBusAction()) || 
					Editor.ACTION_INTERFACE_CONSOLE.equals(editor.getBusAction()) ||
					Editor.ACTION_CREATE_INTERFACE_JSON.equals(editor.getBusAction())
				)
			){//上一次记录输入的时中文，则不触发
				setForegroundColor2();
			}
		}
	}
	
	public void find(String findWord, boolean ignore){
		String text=editor.getText();
		if(ObjectUtils.isEmpty(text)){
			return ;
		}
		text=text.replace(FileUtils.nextLine(), "\n");//\r\n算一个
		if(ignore){
			findWord=findWord.toUpperCase();
			text=text.toUpperCase();
		}
		int start=editor.getSelectionStart();
		int end=editor.getSelectionEnd();
		start=end;
		int findStart=text.indexOf(findWord, start);
		if(findStart!=-1){
			editor.setSelectionStart(findStart);
			editor.setSelectionEnd(findStart+findWord.length());
		}else{
			text=text.substring(0, start);
			findStart=text.indexOf(findWord);
			if(findStart!=-1){
				editor.setSelectionStart(findStart);
				editor.setSelectionEnd(findStart+findWord.length());
			}
		}
	}
	
	public void replace(String findWord, String replaceWord, boolean ignore){
		try {
			String text=editor.getText();
			if(ObjectUtils.isEmpty(text)){
				return ;
			}
			if(ignore){
				findWord=findWord.toUpperCase();
			}
			Element root = getDefaultRootElement();
			int count=root.getElementCount();
			Element row;
			String rowText;
			int findStart, findLength=findWord.length(),startOffset;
			this.isShowQuickTips=false;
			this.isRedrawColor=false;
			int lastReplace=0;
			for (int i = 0; i < count; i++) {
				row=root.getElement(i);
				startOffset = row.getStartOffset();
				rowText=getText(startOffset, row.getEndOffset()-startOffset);
				if(ignore){
					rowText=rowText.toUpperCase();
				}
				while((findStart=rowText.lastIndexOf(findWord))!=-1){
					lastReplace=startOffset+findStart;
					remove(lastReplace, findLength);
					insertString(lastReplace, replaceWord, new SimpleAttributeSet());
					if(findStart==0){
						rowText="";
					}else{
						rowText=rowText.substring(0, findStart);
					}
				}
			}
			lastReplace+=replaceWord.length();
			editor.setSelectionStart(lastReplace);
			editor.setSelectionEnd(lastReplace);
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			setForegroundColor();
			this.isShowQuickTips=true;
			this.isRedrawColor=true;
		}
	}
	
	public void doubleClickSelected(){//双击选中
		try {
			int selectStart=editor.getSelectionStart();
			int selectEnd=editor.getSelectionEnd();
			int length=this.getLength();
			if(selectStart!=selectEnd && selectEnd<length){
				String endChar=getText(selectEnd, 1);
				if(endChar.equals("_")){
					editor.setSelectionEnd(selectEnd+1);
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	private void setForegroundColor(){
		int start=editor.getSelectionStart();
		int end=editor.getSelectionEnd();
		if(start!=end){//开始和结束不相等，则结束
			return ;
		}
		setForegroundColor(editor.getText(), start);//渲染颜色，全部渲染的目的是假如注释输入到一半
	}
	
	private void setForegroundColor(String text, int start){
		if(this.isRedrawColor){
			refreshColor++;
			ThreadUtils.execute(new Runnable() {
				@Override
				public void run() {
					try {
						Thread.sleep(50);
						synchronized (EditorDocument.class) {
							if(refreshColor==1){
								String text=editor.getText();
								text=text.replace(FileUtils.nextLine(), "\n");//\r\n算一个
								StringTokenizer tokens = new StringTokenizer(text, JsonUtils.JSON_SPLIT, true);//拆分
								tokensToForegroundColor(tokens);
							}
							refreshColor--;
						}
					} catch (Exception e) {
						e.printStackTrace();
					}
				}
			});
		}
	}
	
	private void tokensToForegroundColor(StringTokenizer tokens){
		try {
			int start=0, addIndex, length;
			String token, beforeKeyword=null;
			while (tokens.hasMoreTokens()) {
				token=tokens.nextToken();
				if(",:[{".contains(token)){
					beforeKeyword=token;
				}
				addIndex=parseVarchar(tokens, token, start, true, !":".equals(beforeKeyword));
				if(addIndex!=start){
					start=addIndex;
					continue;
				}
				addIndex=parseComment01(tokens, token, start, true);
				if(addIndex!=start){
					start=addIndex;
					continue;
				}
				addIndex=parseOk(tokens, token, start, true);
				if(addIndex!=start){
					start=addIndex;
					continue;
				}
				addIndex=parseError(tokens, token, start, true);
				if(addIndex!=start){
					start=addIndex;
					continue;
				}
				length = token.length();
				if(JsonUtils.isKeyword(token)){
					StyleConstants.setForeground((MutableAttributeSet) attribute, KEYWORD_COLOR);
					setCharacterAttributes(start, length, attribute, true);
				}else if(NumberUtils.isDecimal(token, false)){
					StyleConstants.setForeground((MutableAttributeSet) attribute, NUMBER_COLOR);
					setCharacterAttributes(start, length, attribute, true);
				}else if("true".equals(token)){
					StyleConstants.setForeground((MutableAttributeSet) attribute, OK_COLOR);
					setCharacterAttributes(start, length, attribute, true);
				}else if("false".equals(token)){
					StyleConstants.setForeground((MutableAttributeSet) attribute, ERROR_COLOR);
					setCharacterAttributes(start, length, attribute, true);
				}else{
					StyleConstants.setForeground((MutableAttributeSet) attribute, DEFAULT_COLOR);
					setCharacterAttributes(start, length, attribute, true);
				}
				start+=length;
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	private void setForegroundColor2(){
		int start=editor.getSelectionStart();
		int end=editor.getSelectionEnd();
		if(start!=end){//开始和结束不相等，则结束
			return ;
		}
		setForegroundColor2(editor.getText(), start);//渲染颜色，全部渲染的目的是假如注释输入到一半
	}
	
	private void setForegroundColor2(String text, int start){
		if(this.isRedrawColor){
			refreshColor++;
			ThreadUtils.execute(new Runnable() {
				@Override
				public void run() {
					try {
						Thread.sleep(50);
						synchronized (EditorDocument.class) {
							if(refreshColor==1){
								String text=editor.getText();
								text=text.replace(FileUtils.nextLine(), "\n");//\r\n算一个
								StringTokenizer tokens = new StringTokenizer(text, " ,\f\n\r\t", true);//拆分
								tokensToForegroundColor2(tokens);
							}
							refreshColor--;
						}
					} catch (Exception e) {
						e.printStackTrace();
					}
				}
			});
		}
	}
	
	private void tokensToForegroundColor2(StringTokenizer tokens){
		try {
			int start=0, length;
			String token, findToken;
			while (tokens.hasMoreTokens()) {
				token=tokens.nextToken();
				length = token.length();
				if(token.equals("成功") || token.equals("未发现问题")){
					StyleConstants.setForeground((MutableAttributeSet) attribute, OK_COLOR);
					setCharacterAttributes(start, length, attribute, true);
				}else if(token.equals("失败") || token.equals("异常") || token.equals("警告")){
					do {
						findToken=tokens.nextToken();
						token += findToken;
					} while (!"\n".equals(findToken) && tokens.hasMoreTokens());
					length = token.length();
					StyleConstants.setForeground((MutableAttributeSet) attribute, ERROR_COLOR);
					setCharacterAttributes(start, length, attribute, true);
				}else{
					StyleConstants.setForeground((MutableAttributeSet) attribute, KEYWORD_COLOR);
					setCharacterAttributes(start, length, attribute, true);
				}
				start+=length;
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	private int parseComment01(StringTokenizer tokens, String token, int start, boolean isSetColor){
		if("/".equals(token)){//-- 注释
			if(!tokens.hasMoreTokens()){
				return start;
			}
			int matchLevel=0, matchLevel2=0, length=0;
			do {
				token = tokens.nextToken();
				if(matchLevel==0 && "/".equals(token)){
					matchLevel2++;
					matchLevel=-1;
					length++;
				}else if(matchLevel==0 && "*".equals(token)){
					matchLevel++;
					length++;
				}else if(matchLevel==1 && "*".equals(token)){
					matchLevel=2;
					length++;
				}else if(matchLevel==2 && "/".equals(token)){
					length+=2;
					if(isSetColor){
						StyleConstants.setForeground((MutableAttributeSet) attribute, NOTES_COLOR);
						setCharacterAttributes(start, length, attribute, true);
					}
					return start+length;
				}else if(matchLevel==1 || matchLevel==2){
					matchLevel=1;
					length+=token.length();
				}else if(matchLevel2==1 && "\n".equals(token)){
					length++;
					if(isSetColor){
						StyleConstants.setForeground((MutableAttributeSet) attribute, NOTES_COLOR);
						setCharacterAttributes(start, length, attribute, true);
					}
					return start+length+1;
				}else if(matchLevel2==1){
					length+=token.length();
				}else{
					start++;
					if(isSetColor){
						StyleConstants.setForeground((MutableAttributeSet) attribute, DEFAULT_COLOR);
						setCharacterAttributes(start, token.length(), attribute, true);
					}
					return start+token.length();
				}
			} while (tokens.hasMoreTokens());
			if(!tokens.hasMoreTokens()){
				if(isSetColor){
					StyleConstants.setForeground((MutableAttributeSet) attribute, NOTES_COLOR);
					setCharacterAttributes(start, length, attribute, true);
				}
				return start+length;
			}
		}
		return start;
	}
	
	private int parseOk(StringTokenizer tokens, String token, int start, boolean isSetColor){
		if(token.startsWith("结果：")){//-- 成功
			int length=token.length();
			if(!tokens.hasMoreTokens()){
				StyleConstants.setForeground((MutableAttributeSet) attribute, OK_COLOR);
				setCharacterAttributes(start, length, attribute, true);
				return start+length;
			}
			do {
				token = tokens.nextToken();
				length+=token.length();
			} while (!"\n".equals(token) && tokens.hasMoreTokens());
			StyleConstants.setForeground((MutableAttributeSet) attribute, OK_COLOR);
			setCharacterAttributes(start, length, attribute, true);
			return start+length;
		}
		return start;
	}
	
	private int parseError(StringTokenizer tokens, String token, int start, boolean isSetColor){
		if(token.startsWith("异常：")){//-- 失败
			int length=token.length();
			if(!tokens.hasMoreTokens()){
				StyleConstants.setForeground((MutableAttributeSet) attribute, ERROR_COLOR);
				setCharacterAttributes(start, length, attribute, true);
				return start+length;
			}
			do {
				token = tokens.nextToken();
				length+=token.length();
			} while (!"\n".equals(token) && tokens.hasMoreTokens());
			StyleConstants.setForeground((MutableAttributeSet) attribute, ERROR_COLOR);
			setCharacterAttributes(start, length, attribute, true);
			return start+length;
		}
		return start;
	}
	
	private int parseVarchar(StringTokenizer tokens, String token, int start, boolean isSetColor, boolean keyword) {
		String findToken;
		if ("\"".equals(token)) {
			if(tokens.hasMoreTokens()){
				do {
					findToken = tokens.nextToken();
					token += findToken;
				} while (token.endsWith("\\\"") || (!"\"".equals(findToken) && tokens.hasMoreTokens()));
			}
			int length = token.length();
			if(isSetColor){
				StyleConstants.setForeground((MutableAttributeSet) attribute, keyword?KEYWORD_COLOR:VARCHAR_COLOR);
				setCharacterAttributes(start, length, attribute, true);
			}
			return start+length;
		}
		return start;
	}
	
	
	public void setPushUndo(boolean isPushUndo) {
		this.isPushUndo = isPushUndo;
	}
	public void setNewAction(boolean isNewAction) {
		this.isNewAction = isNewAction;
	}
	@Override
	public String getText() {
		return editor.getText();
	}
	public boolean isShowQuickTips() {
		return isShowQuickTips;
	}
	public void setShowQuickTips(boolean isShowQuickTips) {
		this.isShowQuickTips = isShowQuickTips;
	}
	public boolean isRedrawColor() {
		return isRedrawColor;
	}
	public void setRedrawColor(boolean isRedrawColor) {
		this.isRedrawColor = isRedrawColor;
	}
}
